#include "http_protocol_msg.h"

#include <cctype>
#include <cstdint>
#include <cstdlib>
#include <string>

std::string HttpUtil::CodeReasonPhrases(int code)
{
    std::string content;
    switch (code)
    {
        case 100:
        {
            content = "Continue";
            break;
        }
        case 101:
        {
            content = "Switching Protocols";
            break;
        }
        case 200:
        {
            content = "OK";
            break;
        }
        case 201:
        {
            content = "Created";
            break;
        }
        case 202:
        {
            content = "Accepted";
            break;
        }
        case 203:
        {
            content = "Non-Authoritative Information";
            break;
        }
        case 204:
        {
            content = "No Content";
            break;
        }
        case 205:
        {
            content = "Reset Content";
            break;
        }
        case 206:
        {
            content = "Partial Content";
            break;
        }
        case 300:
        {
            content = "Multiple Choices";
            break;
        }
        case 301:
        {
            content = "Moved Permanently";
            break;
        }
        case 302:
        {
            content = "Found";
            break;
        }
        case 303:
        {
            content = "Seek Other";
            break;
        }
        case 304:
        {
            content = "Not Modified";
            break;
        }
        case 305:
        {
            content = "Use Proxy";
            break;
        }
        case 307:
        {
            content = "Temporary Redirect";
            break;
        }
        case 400:
        {
            content = "Bad Request";
            break;
        }
        case 401:
        {
            content = "Unauthorized";
            break;
        }
        case 402:
        {
            content = "payment Required";
            break;
        }
        case 403:
        {
            content = "Forbidden";
            break;
        }
        case 404:
        {
            content = "Not Found";
            break;
        }
        case 405:
        {
            content = "Method Not Allowed";
            break;
        }
        case 406:
        {
            content = "Not Acceptable";
            break;
        }
        case 407:
        {
            content = "Proxy Authentication Required";
            break;
        }
        case 408:
        {
            content = "Request Time-out";
            break;
        }
        case 409:
        {
            content = "Conflict";
            break;
        }
        case 410:
        {
            content = "Gone";
            break;
        }
        case 411:
        {
            content = "Lnegth Required";
            break;
        }
        case 412:
        {
            content = "Precondition Failed";
            break;
        }
        case 413:
        {
            content = "Request Entity Too Large";
            break;
        }
        case 414:
        {
            content = "Request-URI Too Large";
            break;
        }
        case 415:
        {
            content = "Unsupported Media Type";
            break;
        }
        case 416:
        {
            content = "Request range not satisfiable";
            break;
        }
        case 417:
        {
            content = "Expectation Failed";
            break;
        }
        case 500:
        {
            content = "Internal Server Error";
            break;
        }
        case 501:
        {
            content = "Not Implemented";
            break;
        }
        case 502:
        {
            content = "Bad Gateway";
            break;
        }
        case 503:
        {
            content = "Service Unavailable";
            break;
        }
        case 504:
        {
            content = "Gateway Time-out";
            break;
        }
        case 505:
        {
            content = "Http Version not supported";
            break;
        }
        default:
        {
            code    = code / 100 * 100;
            content = code > 0 ? CodeReasonPhrases(code) : "Unknown Status Code";
            break;
        }
    }
    return content;
}

std::string HttpUtil::ToLower(const std::string & content)
{
    std::string result;
    for (auto & data : content)
    {
        result.push_back(tolower(data));
    }
    return result;
}

HttpRequest::HttpRequest()
{
}

void HttpRequest::AddHeaderLine(const std::string & method, const std::string & uri, const std::string & version)
{
    m_method  = method;
    m_uri     = uri;
    m_version = version;
}

void HttpRequest::AddHeaderSign(const std::string & key, const std::string & value)
{
    auto iter = m_header_sign_map.find(key);
    if (iter == m_header_sign_map.end())
    {
        m_header_sign_map.insert(std::make_pair(key, value));
    }
}

void HttpRequest::AddHeaderBody(const uint8_t * data, int length)
{
    for (int index = 0; index < length; index++)
    {
        m_body_vec.push_back(*(data + index));
    }
}

void HttpRequest::Clear()
{
    m_uri.clear();
    m_method.clear();
    m_version.clear();
    m_header_sign_map.clear();
    m_body_vec.clear();
}

std::string HttpRequest::GetMethod()
{
    return m_method;
}

std::string HttpRequest::GetUri()
{
    return m_uri;
}

std::string HttpRequest::GetVersion()
{
    return m_version;
}

std::string HttpRequest::GetHeaderValue(const std::string & key)
{
    auto iter = m_header_sign_map.find(key);
    if (iter != m_header_sign_map.end())
    {
        return iter->second;
    }
    return "";
}

int HttpRequest::GetContentLength()
{
    std::string content = GetHeaderValue("Content-Length");
    if (content.empty())
    {
        return 0;
    }
    return atoi(content.c_str());
}

std::vector<uint8_t> & HttpRequest::Body()
{
    return m_body_vec;
}

void HttpRequest::String(std::string & content)
{
    if (m_method.empty())
    {
        content = "GET ";
    }
    else
    {
        content = m_method + " ";
    }
    if (m_uri.empty())
    {
        content += "/ ";
    }
    else
    {
        content += m_uri + " ";
    }
    content += "HTTP/1.1\r\n";
    if (!m_header_sign_map.empty())
    {
        for (auto & data : m_header_sign_map)
        {
            content += data.first + ": " + data.second + "\r\n";
        }
    }
    if (!m_body_vec.empty())
    {
        content += "Content-Length: " + std::to_string(m_body_vec.size()) + "\r\n";
    }
    content += "\r\n";
    if (!m_body_vec.empty())
    {
        content.append((const char *)m_body_vec.data(), m_body_vec.size());
    }
}

HttpResponse::HttpResponse()
{
}

std::string HttpResponse::GetCode()
{
    return m_code;
}

std::string HttpResponse::GetVersion()
{
    return m_version;
}

std::string HttpResponse::GetNote()
{
    return m_note;
}

std::vector<uint8_t> & HttpResponse::Body()
{
    return m_body_vec;
}

std::string HttpResponse::GetHeaderValue(const std::string & key)
{
    auto iter = m_header_sign_map.find(key);
    if (iter != m_header_sign_map.end())
    {
        return iter->second;
    }
    return "";
}

void HttpResponse::Clear()
{
    m_version.clear();
    m_code.clear();
    m_note.clear();
    m_body_vec.clear();
    m_header_sign_map.clear();
}

void HttpResponse::AddHeaderLine(const std::string & version, const std::string & code, const std::string & note)
{
    m_version = version;
    m_code    = code;
    m_note    = note;
}

void HttpResponse::AddHeaderSign(const std::string & key, const std::string & value)
{
    m_header_sign_map.insert(std::make_pair(key, value));
}
